/****************************************************************************
 * @file    DataParser.c
 * @brief   Implementation of data parsing utilities using multiple unions
 *          and byte parameters.
 * @details This file implements functions to parse high and low bytes into
 *          various data types using multiple unions.
 *
 * @author  YourName
 * @date    YYYY-MM-DD
 ****************************************************************************/

#include "DataParser.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>


typedef union {
    uint32_t u32;
    int32_t i32;
    float f;
    uint8_t bytes[4];
} DataUnion;
// Static instances of unions for parsing
static U16Union u16Union;
static U32Union u32Union;

uint16_t parse_uint16(uint8_t highByte, uint8_t lowByte)
{
    u16Union.bytes[0] = lowByte;
    u16Union.bytes[1] = highByte;
    return u16Union.u16;
}

int16_t parse_int16(uint8_t highByte, uint8_t lowByte)
{
    u16Union.bytes[0] = lowByte;
    u16Union.bytes[1] = highByte;
    return u16Union.i16;
}

uint32_t parse_uint32(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3)
{
    u32Union.bytes[0] = byte0;
    u32Union.bytes[1] = byte1;
    u32Union.bytes[2] = byte2;
    u32Union.bytes[3] = byte3;
    return u32Union.u32;
}

int32_t parse_int32(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3)
{
    u32Union.bytes[0] = byte0;
    u32Union.bytes[1] = byte1;
    u32Union.bytes[2] = byte2;
    u32Union.bytes[3] = byte3;
    return u32Union.i32;
}

float parse_float(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3)
{
    u32Union.bytes[0] = byte0;
    u32Union.bytes[1] = byte1;
    u32Union.bytes[2] = byte2;
    u32Union.bytes[3] = byte3;
    return u32Union.f32;
}
void uint16_to_bytes(uint16_t value, uint8_t *highByte, uint8_t *lowByte)
{
    *highByte = (uint8_t)(value >> 8);
    *lowByte = (uint8_t)value;
}

void int16_to_bytes(int16_t value, uint8_t *highByte, uint8_t *lowByte)
{
    *highByte = (uint8_t)(value >> 8);
    *lowByte = (uint8_t)value;
}

void uint32_to_bytes(uint32_t value, uint8_t *byte0, uint8_t *byte1, uint8_t *byte2, uint8_t *byte3)
{
    *byte0 = (uint8_t)(value >> 24);
    *byte1 = (uint8_t)(value >> 16);
    *byte2 = (uint8_t)(value >> 8);
    *byte3 = (uint8_t)value;
}

void int32_to_bytes(int32_t value, uint8_t *byte0, uint8_t *byte1, uint8_t *byte2, uint8_t *byte3)
{
    *byte0 = (uint8_t)(value >> 24);
    *byte1 = (uint8_t)(value >> 16);
    *byte2 = (uint8_t)(value >> 8);
    *byte3 = (uint8_t)value;
}

void float_to_bytes(float value, uint8_t *byte0, uint8_t *byte1, uint8_t *byte2, uint8_t *byte3)
{
    DataUnion data;
    data.f = value;
    *byte0 = data.bytes[0];
    *byte1 = data.bytes[1];
    *byte2 = data.bytes[2];
    *byte3 = data.bytes[3];
}


// Modbus CRC16计算函数
uint16_t modbus_crc16(const uint8_t *data, uint16_t length) {
    uint16_t crc = 0xFFFF;  // 初始值
    uint16_t i=0;
    uint8_t j =0;
    for ( i = 0; i < length; i++) {
        crc ^= data[i];  // 先与当前字节异或

        for ( j = 0; j < 8; j++) {  // 处理每个字节的8位
            if (crc & 0x0001) {  // 判断最低位
                crc >>= 1;
                crc ^= 0xA001;  // 如果最低位是1，则与多项式异或
            } else {
                crc >>= 1;  // 如果最低位是0，直接右移
            }
        }
    }

    // 返回最终的CRC16值
    return crc;
}

/*
 * 协议说明
 *
 * 该协议用于数据的封装和解析，其数据格式如下：
 *
 * 数据包格式:
 *
 * [帧头1] [帧头2] [功能码] [长度低字节] [长度高字节] [负载数据] [CRC16校验]
 *
 * 字段说明:
 *
 * - 帧头（2字节）:
 *   - 帧头1: 固定为 0xAA
 *   - 帧头2: 固定为 0x55
 *   - 用于标识数据包的开始，并帮助接收端同步数据包。
 *
 * - 功能码（1字节）:
 *   - 表示数据包的功能或命令类型，例如读数据、写数据等。
 *   - 功能码决定了数据包的具体操作或响应内容。
 *
 * - 长度字段（2字节）:
 *   - 长度低字节: 负载数据的长度的低字节（第一个字节）。
 *   - 长度高字节: 负载数据的长度的高字节（第二个字节）。
 *   - 这两个字节合并在一起表示负载数据的总长度，确保接收端能够正确读取负载数据。
 *
 * - 负载数据（可变长度）:
 *   - 实际需要传输的数据。
 *   - 负载数据的长度由前面的长度字段指定。
 *
 * - CRC16校验（2字节）:
 *   - CRC16（循环冗余校验）用于校验数据包的完整性。
 *   - 计算方式是对从帧头到负载数据的所有字节进行 CRC16 运算，以检测数据在传输过程中是否发生错误。
 *   - CRC16 校验码包括两个字节，低字节在前，高字节在后。
 *
 * 示例:
 *
 * 假设功能码为 0x01，负载数据为 0x123456，则数据包构造如下：
 *
 * 1. 帧头: 0xAA 0x55
 * 2. 功能码: 0x01
 * 3. 长度字段: 负载数据长度 0x06（6 字节），即 0x06 0x00（低字节在前）
 * 4. 负载数据: 0x12 0x34 0x56
 * 5. CRC16 校验: 计算所有前面字节的 CRC16 值，附加在数据包的末尾
 *
 * 数据包最终可能如下（假设 CRC16 计算结果为 0xABCD）:
 *
 * 0xAA 0x55 0x01 0x06 0x00 0x12 0x34 0x56 0xCD 0xAB
 *
 * 解析过程:
 *
 * 在接收端：
 * 1. 检查帧头是否匹配。
 * 2. 读取功能码和长度字段。
 * 3. 读取负载数据，并根据长度字段确定其长度。
 * 4. 计算 CRC16 校验码，并与数据包中的 CRC16 校验码进行比较，验证数据的完整性。
 *
 * 以上协议结构可以用于各种需要数据完整性校验和功能码区分的通信场景。通过确保数据包格式和校验一致性，可以提高通信的可靠性。
 */

// 封装数据包
uint16_t pack_data(uint8_t function_code, const uint8_t *payload, uint16_t payload_len, uint8_t *output_buffer) {
    // 在函数入口定义变量
    uint8_t header[] = {0xAA, 0x55};
    uint16_t total_length;
    uint16_t crc;

    // 计算总长度: header + function_code + length (2字节) + payload + CRC16
    total_length = 2 + 1 + 2 + payload_len + 2;

    // 复制帧头
    memcpy(output_buffer, header, 2);

    // 功能码
    output_buffer[2] = function_code;

    // 长度字段: 先低字节，后高字节
    output_buffer[3] = payload_len & 0xFF;         // 低字节
    output_buffer[4] = (payload_len >> 8) & 0xFF;  // 高字节

    // Payload
    memcpy(output_buffer + 5, payload, payload_len);

    // 计算Modbus CRC16
    crc = modbus_crc16(output_buffer, 5 + payload_len);
    output_buffer[5 + payload_len] = crc & 0xFF;  // CRC低字节
    output_buffer[6 + payload_len] = (crc >> 8);  // CRC高字节

    return total_length;  // 返回整个数据包的长度
}

// 解析数据包
bool parse_data(const uint8_t *input_buffer, uint16_t input_len, uint8_t *function_code, uint8_t *payload, uint16_t *payload_len) {
    // 在函数入口定义变量
    uint16_t received_crc;
    uint16_t computed_crc;

    // 检查数据包的最小长度
    if (input_len < 7) {
        return false;
    }

    // 校验帧头
    if (input_buffer[0] != 0xAA || input_buffer[1] != 0x55) {
        return false;
    }

    // 提取功能码
    *function_code = input_buffer[2];

    // 提取长度字段: 先低字节，后高字节
    *payload_len = input_buffer[3] | (input_buffer[4] << 8);

    // 校验总长度是否符合
    if (*payload_len + 7 != input_len) {
        return false;
    }

    // 提取payload
    memcpy(payload, input_buffer + 5, *payload_len);

    // 提取接收到的CRC16
    received_crc = (input_buffer[5 + *payload_len] & 0xFF) | (input_buffer[6 + *payload_len] << 8);

    // 计算CRC16并校验
    computed_crc = modbus_crc16(input_buffer, 5 + *payload_len);
    if (computed_crc != received_crc) {
        return false;
    }

    return true;
}





void protocol_parser_init(ProtocolParser *parser) {
    // 变量在函数入口定义
    parser->state = STATE_WAIT_HEADER1;
    parser->index = 0;
    parser->expected_length = 0;
}

// 处理接收到的单个字节
uint8_t protocol_parser_receive_byte(ProtocolParser *parser, uint8_t byte) {
    // 定义所有变量在函数入口
    uint16_t computed_crc;
    uint16_t received_crc;

    switch (parser->state) {
        case STATE_WAIT_HEADER1:
            if (byte == 0xAA) {
                parser->buffer[0] = byte;
                parser->state = STATE_WAIT_HEADER2;
                parser->index = 1;
            }
            break;
        case STATE_WAIT_HEADER2:
            if (byte == 0x55) {
                parser->buffer[1] = byte;
                parser->state = STATE_RECEIVE_REMAINING;
                parser->index = 2;
            } else {
                parser->state = STATE_WAIT_HEADER1;
            }
            break;
        case STATE_RECEIVE_REMAINING:
            parser->buffer[parser->index++] = byte;

            // 当接收到功能码和长度字段后，计算预期的总长度
            if (parser->index == 4) {
                parser->expected_length = 6 + (parser->buffer[3] << 8) + parser->buffer[2]; // 帧头2字节 + 功能码1字节 + 长度2字节 + CRC2字节
            }

            // 检查是否接收完一个完整的数据包
            if (parser->index == parser->expected_length) {
                computed_crc = modbus_crc16(parser->buffer, parser->index - 2);
                received_crc = (parser->buffer[parser->index - 1] << 8) | parser->buffer[parser->index - 2];

                // CRC校验
                if (computed_crc == received_crc) {
                    // CRC校验成功，返回 true 表示数据包接收完毕并有效
                    return true;
                } else {
                    // CRC校验失败，重置状态机
                    protocol_parser_init(parser);
                }
            }
            break;
    }

    return false;  // 还没有完成一个完整包
}

// 访问payload数据的指针
uint8_t* get_payload_data(ProtocolParser *parser) {
    return &parser->buffer[4];  // 功能码后面的数据就是payload
}

uint16_t get_payload_length(ProtocolParser *parser) {
    return (parser->buffer[3] << 8) | parser->buffer[2];
}
